/*
 * 文件名称:          PropertyEnableFilter.java
 * 版权所有@ 2016——2017 无锡聆音科技有限公司，保留所有权利
 * 时间:             2016年7月27日 下午9:21:11
 */
package com.lingyin.json.filter;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;

/**
 *  根据对象的属性名判断是否需要json序列化该对象的该属性，即是过滤对象
 *  的某些属性，使其不需要json序列化。
 *  在使用该过滤器的时候可以设置需要过滤的属性，也可以设置不需要过滤的属性。
 *  如果针对一个对象的属性，既设置了过滤属性，又设置了不过滤属性，则以过滤属性优先，
 *  即是在这种情况下，该属性是被过滤掉而不序列化的；
 *  如果仅仅设置了不过滤属性，则只序列化不过滤属性；如果只设置了过滤属性，则该
 *  对象中除了设置的过滤属性外都需要序列化。
 * 
 * @项目        jsonlib
 * 
 * @作者:       关宏新
 * 
 * @日期:       2016年7月27日
 * 
 * @负责人:    关宏新
 * 
 * @负责小组:   聆音项目组
 * 
 */
public class PropertyEnableFilter implements PropertyPreFilter
{
    
    // 记录需要转换的映射类及相关属性关系。
    private Map<String, Set<String>> excludes;
    private Map<String, Set<String>> includes;
    
    /**
     * 
     */
    public PropertyEnableFilter()
    {
    }
    
    /**
     * 构造属性过滤器，如果properties为null，则clazz所有属性都被过滤掉
     * @param clazz 需要过滤的对象
     * @param properties 需要过滤的属性
     */
    public PropertyEnableFilter(Class<?> clazz, String ... properties)
    {
        if (properties == null || clazz == null || properties.length <= 0)
        {
            return;
        }
        includes = new HashMap<String, Set<String>>();
        Set<String> include = new HashSet<String>();        
        for (String item : properties) 
        {
            if (item != null)
            {
                include.add(item);
            }
        }
        includes.put(clazz.getName(), include);
    }
    
    /**
     * 设置不需要过滤的属性，即是需要json序列化的属性，如果properties为null，则clazz所有属性都被过滤掉
     * @param clazz 不需要过滤的对象
     * @param properties 不需要过滤的属性
     */
    public void setEnableProperty(Class<?> clazz, String ... properties)
    {
        if (clazz == null)
        {
            return;
        }
        if (includes == null)
        {
            includes = new HashMap<String, Set<String>>();
        }
        Set<String> include = includes.get(clazz.getName());
        if (include == null)
        {
            include = new HashSet<String>();
            includes.put(clazz.getName(), include);
        }
        for (String item : properties) 
        {
            if (item != null)
            {
                include.add(item);
            }
        }
        
    }
    
    /**
     * 设置需要过滤的属性，即是不需要json序列化的属性
     * @param clazz 需要过滤的对象
     * @param properties 需要过滤的属性
     */
    public void setDisableProperty(Class<?> clazz, String ... properties)
    {
        if (clazz == null)
        {
            return;
        }
        if (excludes == null)
        {
            excludes = new HashMap<String, Set<String>>();
        }
        Set<String> exclude = excludes.get(clazz.getName());
        if (exclude == null) 
        {
            exclude = new HashSet<String>(); 
            excludes.put(clazz.getName(), exclude);
        }
        for (String item : properties) 
        {
            if (item != null)
            {
                exclude.add(item);
            }
        }
        
    }
    
    /**
     * 处理属性名的过滤。
     * @param serializer json序列化对象。
     * @param object 需要转换的对象
     * @param name 需要判断的属性名
     * @return boolean true表示需要序列化，false表示不需要序列化。
     */
    public boolean apply(JSONSerializer serializer, Object object, String name)
    {
        String clazz = object.getClass().getName();
        if (excludes != null)
        {
            Set<String> exclude = excludes.get(clazz);
            if (exclude != null && exclude.contains(name))   // 过滤优先
            {
                return false;
            }
        }

        if (includes != null)  // 不过滤
        {
            Set<String> include = includes.get(clazz);
            return (include == null || include.contains(name));  // 不过滤的属性            
        }

        return true;
    }

}
